/*
 * MIT License
 * 
 * Copyright (c) 2016 wen.gu <454727014@qq.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
 * Name: tiny_ini_file.h
 *
 * Purpose: ini file operation API implementation
 *
 * Developer:
 *   wen.gu , 2016-08-10
 *
 * TODO: 
 *
 ***************************************************************************/

#ifndef __TINY_INI_FILE_H__
#define __TINY_INI_FILE_H__

#ifdef __cplusplus
extern "C"{
#endif

/**
 * ini file 
 * syntax:
 * []     <   section lable,eg. [log.conf]
 * #      <   one line comment
 * ;      <   one line comment
 * =      <   link key(at left) and value(at right),eg. level = debug
 *
 * @note  1. the key in a section is not unique, it mean that, maybe have
 *           several same key in one section.
 *
 * for example:
 *
 * [log.conf] #log print configure
 * level = debug
 * enable_line_number = true
 *
 * ;pluing list
 * [plugin.list]
 * plugin = libfdk_aac_enc.so
 * plugin = libx264_enc.so
 *
 */


/***************************************************************************
 *
 * macro declaration
 *
 ***************************************************************************/
/**
* if ini file havan't any section,then parser will add a default section
* user cann't use this section name,it is reserve section name.
*/

#define DEFAULT_SECTION_NAME "default"

#define SECTION_MAX_COUNT  32  /** maximu section count in one ini file */

#define LINE_BUF_MAX_LEN   1024 /** the expression line maximum length */


/** compat the keyword 'inline' */
#if (_MSC_VER > 1200) && !defined (__cplusplus)
#define inline    _inline  /** to compat keyword 'inline' */
#endif

/***************************************************************************
 *
 * data structure declaration
 *
 ***************************************************************************/

/** base data type define */

//general signed integer type
typedef int                GS32;  //32 bits

//general unsigned integer type
typedef unsigned int       GU32; //32 bits

//boolean type declaration
typedef enum GBOL
{
    GFALSE = 0,
    GTRUE = !GFALSE,
}GBOL;

//general error type define
typedef enum general_error_e
{
    G_OK = 0,

    /** There were insufficient resources to perform the requested operation */
    G_ErrorInsufficientResources = (GS32) 0x80001000,
    /** There was an error, but the cause of the error could not be determined */
    G_ErrorUndefined = (GS32) 0x80001001,
    /** One or more parameters were not valid */
    G_ErrorBadParameter = (GS32)0x80001004,
    G_ErrorInvalidOperation = (GS32)0x8000101C, /** invalid operation */

    /** No target with the specified name string was found */
    G_ErrorNotFound = (GS32)0x80001003,
}general_error_t;



/** ini file data structure define */

typedef struct key_value_pair_s key_value_pair_t;

typedef struct ini_section_s 
{
    int pair_count; /**the conut of pairs in current section */   
    key_value_pair_t* pairs;
    char *name; /** section name */
    void* opaque; /** private data, user cann't modify it */
}ini_section_t;


/** todo, add more function, for example add key-value, add section, save ini */
typedef struct tiny_ini_file_s 
{
    GBOL is_loaded; /** GTRUE: already loaded one file, GFALSE: doesn't */
    void* opaque;
    /*
     *@brief load a ini file
     *
     *@param ini_file  [in] ini file instance pointer
     *@param file_name [in] the name of ini file
     *
     *@return sucess: FRE_OK, fail: error code.
     *
     **/
    GS32(*load)(struct tiny_ini_file_s* ini_file, const char* file_name);

    /*
     *@brief get the value of a key which is first key in the section.
     *
     *@param ini_file [in]  ini file instance pointer
     *@param section  [in]  the name of section
     *@param key      [in]  the name of key
     *@param value    [out] the value of the key
     *
     *@return sucess: FRE_OK, fail: error code.
     *
     *@note maybe have many same key in one section, here just get we find 
     *      the first value with "key"
     *
     **/
    GS32(*getValue)(struct tiny_ini_file_s* ini_file, const char* section, const char* key, char** value);

    /*
     *@brief get all values of a key in the section.
     *
     *@param ini_file [in]  ini file instance pointer
     *@param section  [in]  the name of section
     *@param key      [in]  the name of key
     *@param values   [out] the all values of the key
     *@param count    [out] the count of values
     *
     *@return sucess: FRE_OK, fail: error code.
     *
     *@note 
     *
     **/
    GS32(*getValues)(struct tiny_ini_file_s* ini_file, const char* section, const char* key, char** values[], GU32* count);


    /*
     *@brief free values
     *
     *@param ini_file [in] ini file instance pointer
     *@param values   [in] the values which need to free
     *@param count    [in] the count of values 
     *
     *@return none.
     *
     *@note 
     *
     **/
    void(*freeValues)(struct tiny_ini_file_s* ini_file, char* values[], GU32 count);

    /*
     *@brief get a section with section name.
     *
     *@param ini_file [in]  ini file instance pointer
     *@param name     [in]  the name of section
     *@param key      [in]  the name of key
     *@param section  [out] required section pointer
     *
     *@return sucess: FRE_OK, fail: error code.
     *
     *@note 
     *
     **/
    GS32(*getSection)(struct tiny_ini_file_s* ini_file, const char* name, ini_section_t** section);

    /*
     *@brief detect if there is a key in the current section
     *
     *@param ini_file [in] ini file instance pointer
     *@param section  [in] the name of section
     *@param key      [in] the name of key
     *
     *@return have: GTRUE, haven't: GFALSE
     *
     *@note 
     *
     **/
    GBOL(*hasKey)(struct tiny_ini_file_s* ini_file, const char* section, const char* key);

    /*
     *@brief detect if there is a section
     *
     *@param ini_file [in] ini file instance pointer
     *@param section  [in] the name of section
     *
     *@return have: GTRUE, haven't: GFALSE
     *
     *@note 
     *
     **/
    GBOL(*hasSection)(struct tiny_ini_file_s* ini_file, const char* section);

    /*
     *@brief print all data in ini file
     *
     *@param ini_file [in] ini file instance pointer
     *
     *@return none
     *
     *@note 
     *
     **/
    void(*dump)(struct tiny_ini_file_s* ini_file);


    /*
     *@brief release ini parser
     *
     *@param ini_file  [in]  ini file instance pointer
     *
     *@return none.
     *
     *@note 
     *
     **/
    void(*destroy)(struct tiny_ini_file_s* ini_file);
}tiny_ini_file_t;

/***************************************************************************
 *
 * API declaration
 *
 ***************************************************************************/


#ifdef __cplusplus
}
#endif


#endif //end of __TINY_INI_FILE_H__
